/*
    SMPEG - SDL MPEG Player Library
    Copyright (C) 1999  Loki Entertainment Software
    
    - Modified by Michel Darricau from eProcess <mdarricau@eprocess.fr>  for popcorn -

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/*
 * Copyright (c) 1995 The Regents of the University of California.
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */

/*
 * Portions of this software Copyright (c) 1995 Brown University.
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement
 * is hereby granted, provided that the above copyright notice and the
 * following two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF BROWN
 * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * BROWN UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
 * BASIS, AND BROWN UNIVERSITY HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
 * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */


/*
   Changes to make the code reentrant:
     Got rid of setjmp, longjmp
     deglobalized: EOF_flag, FilmState, curVidStream, bitOffset, bitLength,
     bitBuffer, sys_layer, input, seekValue, window, X Windows globals (to
     xinfo), curBits, ditherType, matched_depth, totNumFrames, realTimeStart

   Additional changes:
     Ability to play >1 movie (w/out CONTROLS)
     Make sure we do a full frame for each movie
     DISABLE_DITHER #ifdef to avoid compiling dithering code
     Changes to deal with non-MPEG streams
     Now deals with NO_DITHER, PPM_DITHER and noDisplayFlag==1
     CONTROLS version now can deal with >1 movie
   -lsh@cs.brown.edu (Loring Holden)
*/


#include <limits.h>
#include <string.h>

#include "video.h"
#include "proto.h"
#include "dither.h"
#include "util.h"

#include "m1vdec.h"

/*--------------------------------------------------------------*/


/* Define buffer length. */
#define BUF_LENGTH M1VDEC_BUFFER_SIZE


/* TODO: Eliminate these globals so multiple movies can be played. */

/* Quiet flag (verbose). */
int quietFlag = 1;

/* Framerate, -1: specified in stream (default)
               0: as fast as possible
               N (N>0): N frames/sec  
               */
#ifdef TIME_MPEG
int framerate = 0;
#else
int framerate = -1;
#endif

/* Flag for high quality at the expense of speed */
#ifdef M1VDEC_QUALITY
int qualityFlag = 1;
#else
int qualityFlag = 0;
#endif

/*--------------------------------------------------------------*/

LWMPEG_MPEGvideo::LWMPEG_MPEGvideo(LWMPEG_MPEGstream *stream, int target_bpp, const LWMPEG_Allocator *alloc)
{
    Uint32 start_code;

    _fatalError = false;
	_alloc = *alloc;

    /* Set the MPEG data stream */
    mpeg = stream;

    /* Set default playback variables */
    _stream = NULL;

    /* Get the width and height of the video */
    Uint8 peeked_code[4];
    mpeg->peek_bytes(peeked_code, 4);
    start_code = ((peeked_code[0] << 24) | (peeked_code[1] << 16) | (peeked_code[2] << 8) | (peeked_code[3]));

    while ( ! mpeg->eof() && (start_code != SEQ_START_CODE) ) {
		Uint8 pit;
        start_code <<= 8;
		mpeg->copy_data(&pit, 1);
		mpeg->peek_bytes(peeked_code, 4);
        start_code |= peeked_code[2];
    }
    if ( start_code == SEQ_START_CODE ) {
        Uint8 buf[8];

        /* Get the width and height of the video */
        mpeg->peek_bytes(buf, 8);
        _w = (buf[4]<<4)|(buf[5]>>4);    /* 12 bits of width */
        _h = ((buf[5]&0xF)<<8)|buf[6];   /* 12 bits of height */
	switch(buf[7]&0xF)                /*  4 bits of fps */
	{
	  case 1: _fps = 23.97f; break;
	  case 2: _fps = 24.00f; break;
	  case 3: _fps = 25.00f; break;
	  case 4: _fps = 29.97f; break;
	  case 5: _fps = 30.00f; break;
	  case 6: _fps = 50.00f; break;
	  case 7: _fps = 59.94f; break;
	  case 8: _fps = 60.00f; break;
	  case 9: _fps = 15.00f; break;
	  default: _fps = 30.00f; break;
	}
    } else {
        _w = 0;
        _h = 0;
		_fps = 0.00;
        SetError("Not a valid MPEG video stream");
    }

    /* Keep original width and height in _ow and _oh */
    _ow = _w;
    _oh = _h;

    /* Now round up width and height to a multiple   */
    /* of a macroblock size (16 pixels) to keep the  */
    /* video decoder happy */
    _w = (_w + 15) & ~15;
    _h = (_h + 15) & ~15;

	_target_bpp = target_bpp;

	_imgAvailable = false;

//	printf("[MPEGvideo::MPEGvideo]_filter_mutex[%lx] = SDL_CreateMutex()\n",_filter_mutex);
}

LWMPEG_MPEGvideo:: ~LWMPEG_MPEGvideo()
{
    /* Free actual video stream */
    if( _stream )
        DestroyVidStream( _stream, &_alloc );
}

void LWMPEG_MPEGvideo::SetFrameSkip( int frames )
{
	if ( _stream )
		_stream->_skipFrame = frames;
}


bool LWMPEG_MPEGvideo::DecodeFrame()
{
    if ( !_stream ) {
        decodeInitTables();

        InitCrop();
        InitIDCT();

        _stream = NewVidStream( (unsigned int) BUF_LENGTH, &_alloc );
        if( _stream ) {
            _stream->_smpeg        = this;
            _stream->ditherType    = FULL_COLOR_DITHER;
            _stream->matched_depth = _target_bpp;

            if( mpegVidRsrc( 0, _stream, 1 ) == NULL ) {
                SetError("Not an MPEG video stream");
                _fatalError = true;
                return false;
            }
        }
		else {
            SetError("Video stream initialization failed");
            _fatalError = true;
            return false;
		}

        if ( ! InitPictImages(_stream, _w, _h, &_alloc) )
            return false;
		return true;
    }
	else
	{
		if( mpegVidRsrc( 0, _stream, 0 ) == NULL )
		{
			_fatalError = true;
			return false;
		}
		return (_stream->EOF_flag == 0);
	}
}



/* EOF */
